package com.google.code.jholidays.plugins.utils;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

/**
 * Represents reflection helper.
 * 
 * @author tillias
 * 
 */
public class Reflector {

    /**
     * Gets current working path
     * 
     * @return Current working path
     */
    public String getWorkingPath() {
	return System.getProperty("user.dir");
    }

    /**
     * Gets list of all JAR files (having *.jar extension) using given path.
     * 
     * @param path
     *            Search path
     * @return List of all JAR files (having *.jar extension)
     */
    public List<File> getJarFiles(String path) {
	List<File> result = new ArrayList<File>();

	File dir = new File(path);

	if (dir.exists()) {
	    File[] files = dir.listFiles(new JarFileFilter());
	    for (File f : files) {
		result.add(f);
	    }
	}

	return result;
    }

    /**
     * Gets all class names from given JAR file. ".class" symbols are omitted.
     * 
     * @param jarFile
     *            JAR file
     * @return All class names from given file
     */
    public List<String> getClassNames(File jarFile) {
	List<String> result = new ArrayList<String>();

	if (jarFile != null && jarFile.exists()) {
	    // attempt to open file as JAR
	    try {
		JarInputStream jarStream = new JarInputStream(
			new FileInputStream(jarFile));

		JarEntry jarEntry = null;
		while (true) {
		    jarEntry = jarStream.getNextJarEntry();

		    if (jarEntry == null)
			break;

		    String entryName = jarEntry.getName();
		    if (entryName.endsWith(".class")) {
			result.add(entryName.replace('/', '.').replace(
				".class", ""));
		    }
		}
	    } catch (Exception e) {
		result.clear();
	    }
	}

	return result;
    }

    /**
     * Checks whether specified class implements specified interface
     * 
     * @param iClass
     *            Class to be tested if it implements interface
     *            <code>iInterface</code>
     * @param iInterface
     *            Interface which will be used during <code>iClass</code>
     *            compliance test
     * @return True if given <code>iClass</code> implements interface
     *         <code>iInterface</code>
     */
    public boolean implementsInterface(Class<?> iClass, Class<?> iInterface) {
	boolean result = false;

	if (iClass != null && iInterface != null) {
	    try {
		/*
		 * We force get interfaces of iClass since iInterface might not
		 * be interface itself
		 */
		Class<?>[] interfaces = iClass.getInterfaces();

		if (interfaces != null && interfaces.length > 0) {
		    for (Class<?> i : interfaces) {

			/*
			 * interface "i" is guaranteed to be an interface. So if
			 * iInterface is interface itself is should be
			 * assignable form of "i"
			 */
			if (iInterface.isAssignableFrom(i)) {
			    result = true;
			    break;
			}
		    }
		}
	    } catch (Exception e) {
		// nothing to do here
	    }
	}

	return result;
    }
}
